package com.ncr.travel.airline.shared.configuration.checkin;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;

import com.ncr.travel.airline.shared.configuration.converters.AirportCountryMapper;
import com.ncr.travel.airline.shared.configuration.converters.AirportCountryMapperImpl;
import com.ncr.travel.airline.shared.configuration.converters.CountryAirportCode;
import com.ncr.travel.airline.shared.configuration.converters.CountryAirportCode.CountryReference;
import com.ncr.travel.airline.shared.configuration.converters.CountryCodeConverter;
import com.ncr.travel.airline.shared.configuration.converters.CountryCodeConverterImpl;
import com.ncr.travel.airline.shared.configuration.converters.FeatureSettings;
import com.ncr.travel.tas.configuration.management.ConfigurationInitializationException;
import com.ncr.travel.tas.configuration.model.ConfigurationValue;
import com.ncr.travel.tas.configuration.model.ConfigurationValueTemplate;
import com.ncr.travel.tas.shared.configuration.ConfigurationKey;
import com.ncr.travel.tas.shared.configuration.ConfigurationNodeEnum;
import com.ncr.travel.tas.shared.configuration.ConfigurationProductKey;
import com.ncr.travel.tas.shared.configuration.ConfigurationServiceException;

/**
 * 
 *
 */
public class SharedCheckInConfigurationImpl extends CommonCheckInConfigurationImpl 
    implements InitializingBean, SharedCheckInConfiguration {

	private final static Logger logger = LoggerFactory.getLogger(SharedCheckInConfigurationImpl.class);

	private final CountryAirportCode countryAirportCode = new CountryAirportCode();
//
//	/**
//	 * Initializes a new instance of the <code>SharedCheckInConfigurationImpl</code> class.
//	 */
//	public SharedCheckInConfigurationImpl(ConfigurationService configurationService) {
//        setConfigurationService(configurationService);
//	}

	protected Set<ConfigurationValue> loadChildrenValueFromService(ConfigurationNodeEnum type, ConfigurationProductKey product, ConfigurationKey key) {
		logger.info("Loading configuration child values for " + key + " in product " + product + "...");
		ConfigurationValue value = loadValueFromService(type, product, key);
		return value.getChildValues();
	}

	@Override
	public boolean isFeatureOn(CheckInFeature feature) {
		try {
			switch (feature) {
			//Find Res
			//is find by confirmation number enabled for web checkin
			case FIND_RESERVATION_BY_CONFIRMATION_NUMBER:
				return (Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.FIND_BY_OPTIONS).findChild("CONFIRMATION").getValue();
				//is find by ticket number enabled for web checkin
			case FIND_RESERVATION_BY_TICKET_NUMBER:
				return (Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.FIND_BY_OPTIONS).findChild("TICKET").getValue();
				// is find by loyalty number enabled for web checkin
			case FIND_RESERVATION_BY_LOYALTY_PROGRAM:
				return (Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.FIND_BY_OPTIONS).findChild("LOYALTY").getValue();
				// is find by credit card enabled for web checkin
			case FIND_RESERVATION_BY_CARD:
				return (Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.FIND_BY_OPTIONS).findChild("CARD").getValue();
				// is trip validation enabled for the system
			case RESERVATION_VALIDATION_TRIP:
				return (Boolean) loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.VALIDATIONS).findChild(ConfigurationKey.TRIP_VALIDATIONS).getValue();
			case RESERVATION_VALIDATION_TICKET:
				return (Boolean) loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.VALIDATIONS).findChild("PNR_VALIDATIONS").findChild("TicketValidation").getValue();
				//TODO:case RESERVATION_VALIDATION_SSR:
				// is lap infant enabled for the system
			case RESERVATION_VALIDATION_CHECK_IN_TIMES:
				return (Boolean) loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.VALIDATIONS).findChild("PNR_VALIDATIONS").findChild("CheckInTimeValidation")
						.getValue();
			case LAP_INFANT:
				return (Boolean) loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.LAP_INFANT).getValue();
				// is add lap infant enabled for the system
			case LAP_INFANT_UPDATE:
				return !loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.LAP_INFANT).getTemplate().isReadOnly();
				// is lap infant enabled for the system
			case LAP_INFANT_ETICKET:
				return (Boolean) loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.LAP_INFANT).findChild("ETicket").getValue();
				// is lap infant age range enabled for the system
			case LAP_INFANT_AGE_IN_MONTHS:
				return (Boolean) loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.LAP_INFANT).findChild("Age").getValue();
				// is lap infant age by birth date enabled for the system
			case LAP_INFANT_BIRTH_DATE:
				return (Boolean) loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.LAP_INFANT).findChild("BirthDate").getValue();
				// does the system support partner airlines
			case LOYALTY_PROGRAMS_SUPPORT_PARTNER_AIRLINES:
				return (Boolean) loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.VALIDATIONS).findChild(ConfigurationKey.LOYALTY)
						.findChild(ConfigurationKey.SUPPORT_PARTNER_AIRLINE).getValue();
				// does the web checkin support advice to passenger
			case ADVICE_TO_PASSENGER:
				return (Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.THANK_YOU_SCREEN).findChild("AdviceToPassenger").getValue();
				// does the system accept loyalty number
			case CONFIRMATION_NUMBER:
				return (Boolean) loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.VALIDATIONS).findChild(ConfigurationKey.CONFIRMATION_NUMBER).getValue();
				// does the system support ticket number
			case TICKET:
				return (Boolean) loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.VALIDATIONS).findChild(ConfigurationKey.TICKET).getValue();
				// does the system accept loyalty number
			case LOYALTY:
				return (Boolean) loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.VALIDATIONS).findChild(ConfigurationKey.LOYALTY).getValue();
			case LOYALTY_PROGRAM_VISIBLE:
				return (Boolean) loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.VALIDATIONS).findChild(ConfigurationKey.LOYALTY).getValue();
			case CHANGE_SEAT:
				return (Boolean) loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.VALIDATIONS).findChild(ConfigurationKey.CHANGE_SEAT).getValue();
			case ADD_BAGS:
				return (Boolean) loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.VALIDATIONS).findChild(ConfigurationKey.ADD_BAGS).getValue();
			case AQQ:
				return (Boolean) loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.AQQ).getValue();
			case INTERNATIONAL_DOCUMENTS:
				return (Boolean) loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.INTERNATIONAL_DOCUMENTS).getValue();
			case RE_ENTRY:
				return (Boolean) loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.RE_ENTRY).getValue();	
			case GROUP_CHECKIN:
				ConfigurationValue featureValue = getGroupCheckInSettings();
				return ((Boolean) featureValue.getValue()).booleanValue();	
			case REDRESS_NUMBER:
				return (Boolean) loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.INTERNATIONAL_DOCUMENTS).findChild("RedressNumber").getValue();
			case PRINT_BP_PASSENGER_NAME:
				return 	(Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.PRINT_OPTIONS).findChild("BoardingPass").findChild("PassengerName").getValue();
			case PRINT_BP_FFN_STATUS_LEVEL:
				return 	(Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.PRINT_OPTIONS).findChild("BoardingPass").findChild("FfNumberStatusLevel").getValue();
			case PRINT_BP_PREMIER_ACCESS:
				return 	(Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.PRINT_OPTIONS).findChild("BoardingPass").findChild("PremierAccess").getValue();
			case PRINT_BP_CARRIER_CODE:
				return 	(Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.PRINT_OPTIONS).findChild("BoardingPass").findChild("CarrierCode").getValue();
			case PRINT_BP_FLIGHT_NUMBER:
				return 	(Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.PRINT_OPTIONS).findChild("BoardingPass").findChild("FlightNumber").getValue();
			case PRINT_BP_CLASS_OF_SERVICE:
				return 	(Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.PRINT_OPTIONS).findChild("BoardingPass").findChild("ClassOfService").getValue();
			case PRINT_BP_ORIGIN:
				return 	(Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.PRINT_OPTIONS).findChild("BoardingPass").findChild("Origin").getValue();
			case PRINT_BP_DESTINATION:
				return 	(Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.PRINT_OPTIONS).findChild("BoardingPass").findChild("Destination").getValue();
			case PRINT_BP_DEPARTURE_TIME:
				return 	(Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.PRINT_OPTIONS).findChild("BoardingPass").findChild("DepartureTime").getValue();
			case PRINT_BP_GATE_NUMBER_MESSAGE:
				return 	(Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.PRINT_OPTIONS).findChild("BoardingPass").findChild("GateNumberMessage").getValue();
			case PRINT_BP_BAR_CODE:
				return 	(Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.PRINT_OPTIONS).findChild("BoardingPass").findChild("BarCode").getValue();
			case PRINT_BP_SEAT_ASSIGNMENT:
				return 	(Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.PRINT_OPTIONS).findChild("BoardingPass").findChild("SeatAssignment").getValue();
			case PRINT_BP_CONFIRMATION_NUMBER:
				return 	(Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.PRINT_OPTIONS).findChild("BoardingPass").findChild("ConfirmationNumber").getValue();
			case PRINT_BP_TICKET_NUMBER:
				return 	(Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.PRINT_OPTIONS).findChild("BoardingPass").findChild("TicketNumber").getValue();
			case PRINT_BP_CARRIER_LOGO:
				return 	(Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.PRINT_OPTIONS).findChild("BoardingPass").findChild("CarrierLogo").getValue();
			case PRINT_BP_STAR_ALLIANCE_LOGO:
				return 	(Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.PRINT_OPTIONS).findChild("BoardingPass").findChild("StarAllianceLogo").getValue();
			case PRINT_BP_SEQUENCE_NUMBER:
				return 	(Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.PRINT_OPTIONS).findChild("BoardingPass").findChild("SequenceNumber").getValue();
			case PRINT_BP_TICKET_TYPE:
				return 	(Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.PRINT_OPTIONS).findChild("BoardingPass").findChild("TicketType").getValue();
			case PRINT_BP_FREQUENT_FLYER_MILEAGE:
				return 	(Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.PRINT_OPTIONS).findChild("BoardingPass").findChild("FrequentFlyerMileage").getValue();
			case PRINT_BP_BAG_COUNT:
				return 	( 0 != (Integer) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.PRINT_OPTIONS).findChild("BoardingPass").findChild("BagCount").getValue());
			case PRINT_BP_API_OK_NO_API:
				return 	(Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.PRINT_OPTIONS).findChild("BoardingPass").findChild("ApiOkNoApi").getValue();
			case PRINT_BP_OPTIONAL_TEXT_FIELD:
				return 	(Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.PRINT_OPTIONS).findChild("BoardingPass").findChild("OptionalTextField").getValue();
			
			}
		} catch (ConfigurationServiceException e) {
			logger.error(e.getMessage());
			return false;
		}
		return false;
	}
	
	

	@Override
	public boolean isFindByOptionalFieldOn(CheckInFeature feature, FindByOptionalField field) {
		try {
			switch (feature) {
			case FIND_RESERVATION_BY_CONFIRMATION_NUMBER:
				return isFindByOptionalFieldOn("CONFIRMATION", field);
			case FIND_RESERVATION_BY_TICKET_NUMBER:
				return isFindByOptionalFieldOn("TICKET", field);
			case FIND_RESERVATION_BY_CARD:
				return isFindByOptionalFieldOn("CARD", field);
			case FIND_RESERVATION_BY_LOYALTY_PROGRAM:
				return isFindByOptionalFieldOn("LOYALTY", field);
			}
		} catch (ConfigurationServiceException cse) {
			logger.error(cse.getMessage());
			return false;
		}
		return false;
	}

	private boolean isFindByOptionalFieldOn(String feature, FindByOptionalField field) {
		switch (field) {
		case LAST_NAME:
			return (Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.FIND_BY_OPTIONS).findChild(feature).findChild(FindByOptionalField.LAST_NAME.toString())
					.getValue();
		case FIRST_NAME:
			return (Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.FIND_BY_OPTIONS).findChild(feature).findChild(FindByOptionalField.FIRST_NAME.toString())
					.getValue();
		case DEPARTURE_CITY:
			return (Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.FIND_BY_OPTIONS).findChild(feature)
					.findChild(FindByOptionalField.DEPARTURE_CITY.toString()).getValue();
		case ARRIVAL_CITY:
			return (Boolean) loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.FIND_BY_OPTIONS).findChild(feature)
					.findChild(FindByOptionalField.ARRIVAL_CITY.toString()).getValue();
		default:
			return false;
		}
	}

	public ConfigurationValueTemplate getTemplateForOptionslField(String feature, FindByOptionalField field)
	{
		switch (field) {
		case LAST_NAME:
			return loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.FIND_BY_OPTIONS).findChild(feature).findChild(FindByOptionalField.LAST_NAME.toString())
					.getTemplate();
		case FIRST_NAME:
			return loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.FIND_BY_OPTIONS).findChild(feature).findChild(FindByOptionalField.FIRST_NAME.toString())
					.getTemplate();
		case DEPARTURE_CITY:
			return loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.FIND_BY_OPTIONS).findChild(feature).findChild(FindByOptionalField.DEPARTURE_CITY.toString())
					.getTemplate();
		case ARRIVAL_CITY:
			return loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.FIND_BY_OPTIONS).findChild(feature).findChild(FindByOptionalField.ARRIVAL_CITY.toString())
					.getTemplate();
		default:
			return null;
		}
	}

	@Override
	public ConfigurationValueTemplate getTemplateForOptionslField(
			CheckInFeature findByOption, FindByOptionalField field) {
		switch (findByOption) {
		case FIND_RESERVATION_BY_CONFIRMATION_NUMBER:
			return getTemplateForOptionslField("CONFIRMATION", field);
		case FIND_RESERVATION_BY_TICKET_NUMBER:
			return getTemplateForOptionslField("TICKET", field);
		case FIND_RESERVATION_BY_CARD:
			return getTemplateForOptionslField("CARD", field);
		case FIND_RESERVATION_BY_LOYALTY_PROGRAM:
			return getTemplateForOptionslField("LOYALTY", field);
		default:
			return null;
		}
	}

	protected String getConfirmationNumberRegex() {
		ConfigurationValue findByOptions = loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.FIND_BY_OPTIONS);
		ConfigurationValue optionValue = findByOptions.findChild("CONFIRMATION");
		ConfigurationValue value = optionValue.findChild("Regex");
		return (String) value.getValue();
	}

	protected String getTicketNumberRegex() {
		ConfigurationValue findByOptions = loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.FIND_BY_OPTIONS);
		ConfigurationValue optionValue = findByOptions.findChild("TICKET");
		ConfigurationValue value = optionValue.findChild("Regex");
		return (String) value.getValue();
	}

	protected String getLoyaltyNumberRegex() {
		ConfigurationValue findByOptions = loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.FIND_BY_OPTIONS);
		ConfigurationValue optionValue = findByOptions.findChild("LOYALTY");
		ConfigurationValue value = optionValue.findChild("Regex");
		return (String) value.getValue();
	}

	protected String getCardRegex() {
		ConfigurationValue findByOptions = loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.FIND_BY_OPTIONS);
		ConfigurationValue optionValue = findByOptions.findChild("CARD");
		ConfigurationValue value = optionValue.findChild("Regex");
		return (String) value.getValue();
	}

	protected Integer getConfirmationNumberMaxValue() {
		ConfigurationValue findByOptions = loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.FIND_BY_OPTIONS);
		ConfigurationValue optionValue = findByOptions.findChild("CONFIRMATION");
		ConfigurationValue value = optionValue.findChild("MaximumLength");
		return valueToInt(value.getValue());
	}

	protected Integer getCardMaxValue() {
		ConfigurationValue findByOptions = loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.FIND_BY_OPTIONS);
		ConfigurationValue optionValue = findByOptions.findChild("CARD");
		ConfigurationValue value = optionValue.findChild("MaximumLength");
		return valueToInt(value.getValue());
	}

	protected Integer getLoyaltyNumberMaxValue() {
		ConfigurationValue findByOptions = loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.FIND_BY_OPTIONS);
		ConfigurationValue optionValue = findByOptions.findChild("LOYALTY");
		ConfigurationValue value = optionValue.findChild("MaximumLength");
		return valueToInt(value.getValue());
	}

	protected Integer getTicketNumberMaxValue() {
		ConfigurationValue findByOptions = loadValueFromService(ConfigurationNodeEnum.WEB, ConfigurationProductKey.WEB_CHECKIN, ConfigurationKey.FIND_BY_OPTIONS);
		ConfigurationValue optionValue = findByOptions.findChild("TICKET");
		ConfigurationValue value = optionValue.findChild("MaximumLength");
		return valueToInt(value.getValue());
	}

	protected Integer valueToInt(Object value) {
		if (value instanceof Integer) {
			return (Integer) value;
		}
		if (value instanceof String) {
			return Integer.parseInt((String) value);
		}

		return null;
	}

	@Override
	public ConfigurationValueTemplate getTemplateForField(CheckInField field) {
		// FIXME: Refactor this so that templates are read from config service or shared service?
		ConfigurationValueTemplate template = new ConfigurationValueTemplate();
		switch (field) {
		/*case CONFIRMATION_NUMBER:
			template.setRegularExpression(this.getConfirmationNumberRegex());
			template.setMaximumValue(this.getConfirmationNumberMaxValue());
			break;*/
		case CREDIT_CARD_NUMBER:
			template.setRegularExpression(this.getCardRegex());
			template.setMaximumValue(this.getCardMaxValue());
			break;
		case INFANT_ETICKET:
			return loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.LAP_INFANT).findChild("ETicket").getTemplate();
		case INFANT_AGE:
			return loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.LAP_INFANT).findChild("Age").getTemplate();
		case INFANT_BIRTH_DATE:
			return loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.LAP_INFANT).findChild("BirthDate").getTemplate();
		case CONFIRMATION_NUMBER:
			return loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.VALIDATIONS).findChild(ConfigurationKey.CONFIRMATION_NUMBER).getTemplate();
		case TICKET_NUMBER:
			return loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.VALIDATIONS).findChild(ConfigurationKey.TICKET).getTemplate();
		case LOYALTY_NUMBER:
			return loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.VALIDATIONS).findChild(ConfigurationKey.LOYALTY).getTemplate();
		}
		return template;
	}

	@Override
	public List<String> getPartnerAirlines() {
		ConfigurationValue value = this.loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.AIRLINES);

		List<String> airlineCodes = new ArrayList<String>();
		Set<ConfigurationValue> airlineValues = value.getChildValues();
		for (ConfigurationValue airlineValue : airlineValues) {
			ConfigurationValue codeValue = airlineValue.findChild(ConfigurationKey.CODE);
			if (codeValue != null) {
				airlineCodes.add((String) codeValue.getValue());
			}
		}
		return airlineCodes;
	}

	@Override
	public ConfigurationValueTemplate getPartnerAirlineTemplateForField(String airlineCode, PartnerAirlineField field) {
		ConfigurationValue value = this.loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.AIRLINES);
		Set<ConfigurationValue> airlineValues = value.getChildValues();
		for (ConfigurationValue airlineValue : airlineValues) {
			ConfigurationValue codeValue = airlineValue.findChild(ConfigurationKey.CODE);
			if (airlineCode != null && codeValue != null && airlineCode.equals(codeValue.getValue())) {
				//we found the airline 
				switch (field) {
				case LOYALTY_NUMBER:
					ConfigurationValue fieldValue = airlineValue.findChild(ConfigurationKey.LOYALTY);
					if (fieldValue == null) {
						logger.error("Unable to find Loyalty info (for " + airlineCode + ") under: " + ConfigurationKey.LOYALTY);
						return null;
					}
					return fieldValue.getTemplate();
				}

			}
		}
		return null;
	}

	@Override
	public String getHostAirlineCode() {
		ConfigurationValue value = loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.HOST_AIRLINE);
		ConfigurationValue codeValue = value.findChild(ConfigurationKey.CODE);
		return (String) codeValue.getValue();

	}

	@Override
	public String getHostAirlineName() {
		ConfigurationValue value = loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.HOST_AIRLINE);
		ConfigurationValue codeValue = value.findChild(ConfigurationKey.NAME);
		return (String) codeValue.getValue();
	}

	@Override
	public String getHostAirlineLoyaltyProgramName() {
		ConfigurationValue value = loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.HOST_AIRLINE);
		ConfigurationValue codeValue = value.findChild(ConfigurationKey.LOYALTY_PROGRAM_NAME);
		return (String) codeValue.getValue();
	}

	@Override
	public Set<ConfigurationValue> getConfigurationChildren(CheckInConfiguration node) {
		switch (node) {
		case PARTNER_AIRLINES:
			return loadChildrenValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.AIRLINES);
		}
		return null;
	}

	@Override
	public int getMinimumMinutesToConnectToFlight() {
		ConfigurationValue value = loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.VALIDATIONS).findChild(ConfigurationKey.TRIP_VALIDATIONS);
		ConfigurationValue codeValue = value.findChild("TripMinConnectionTime");
		return (Integer) codeValue.getValue();
	}

	@Override
	public int getMaximumMinutesToConnectToFlight() {
		ConfigurationValue value = loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.VALIDATIONS).findChild(ConfigurationKey.TRIP_VALIDATIONS);
		ConfigurationValue codeValue = value.findChild("TripMaxConnectionTime");
		return (Integer) codeValue.getValue();
	}

	@Override
	public List<String> getAcceptableSegmentStatusCodes() {
		List<String> codes = new ArrayList<String>();

		ConfigurationValue value = loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.EXTERNAL_SYSTEMS);
		ConfigurationValue hostValue = value.findChild("PrimaryHost");
		ConfigurationValue statusCodes = hostValue.findChild("AcceptableSegmentStatusCodes");

		for (ConfigurationValue codeValue : statusCodes.getChildValues()) {
			codes.add((String) codeValue.getValue());
		}

		return codes;
	}

	/**
	 * @see SharedCheckInConfiguration#getFlightSegmentStatusCodeMappings()
	 */
	@Override
	public Map<String, Integer> getFlightSegmentStatusCodeMappings() {
       ConfigurationValue value = loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.EXTERNAL_SYSTEMS);
        ConfigurationValue hostValue = value.findChild("PrimaryHost");
        if (hostValue == null) {
            throw new ConfigurationInitializationException("Could not find config value for parent: PrimaryHost");
        }
        ConfigurationValue statusCodes = hostValue.findChild("AcceptableSegmentStatusCodes");
        
        Map<String, Integer> flightSegmentStatusCodeMappings = new ConcurrentHashMap<String, Integer>();
        for (ConfigurationValue codeConfig : statusCodes.getChildValues()) {
            String code = codeConfig.getKeyName();
            flightSegmentStatusCodeMappings.put(code, (Integer)codeConfig.getValue());
        }

		return flightSegmentStatusCodeMappings;
	}

	/**
	 * Required implementation.
	 *
	 * @see SharedCheckInConfiguration#getInhibitedSsrCodes()
	 */
	@Override
	public List<String> getInhibitedSsrCodes() {
		ConfigurationValue ssrParent = loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.SSR);
		ConfigurationValue inhibitionList = ssrParent.findChild("BPInhibitingSsrs");

		if (null == inhibitionList) {
			throw new ConfigurationServiceException("Unable to find SSR values used to inhibit boarding pass generation", null);
		}

		List<String> enabledCodes = new ArrayList<String>();
		for (ConfigurationValue ssrValue : inhibitionList.getChildValues()) {
			Boolean enabled = (Boolean) ssrValue.getValue();
			if (Boolean.TRUE == enabled) {
				enabledCodes.add(ssrValue.getKeyName());
			}
		}

		return enabledCodes;
	}

	/**
	 * Required implementation.
	 *
	 * @see SharedCheckInConfiguration#getUnacceptableSsrCodes()
	 */
	@Override
	public List<String> getUnacceptableSsrCodes() {
		ConfigurationValue ssrParent = loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.SSR);
		ConfigurationValue unacceptableList = ssrParent.findChild("UnacceptableSsrCodes");

		if (null == unacceptableList) {
			throw new ConfigurationServiceException("Unable to find SSR values used to prohibit check-in", null);
		}

		List<String> enabledCodes = new ArrayList<String>();
		for (ConfigurationValue ssrValue : unacceptableList.getChildValues()) {
			Boolean enabled = (Boolean) ssrValue.getValue();
			if (Boolean.TRUE == enabled) {
				enabledCodes.add(ssrValue.getKeyName());
			}
		}

		return enabledCodes;
	}

	/**
	 * Required implementation.
	 *
	 * @see SharedCheckInConfiguration#getDecisionTableConfiguration(String)
	 */
	@Override
	public ConfigurationValue getDecisionTableConfiguration(String tableName) {
		// Get top-level configuration
		ConfigurationValue tableParent = loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.DECISION_TABLES);
		ConfigurationValue requestedTable = null;

		// Find the matching value (if one exists)
		Set<ConfigurationValue> tableDefinitions = tableParent.getChildValues();
		for (ConfigurationValue tableValue : tableDefinitions) {
			if ((null != tableName) && tableName.equals(tableValue.getKeyName())) {
				requestedTable = tableValue;
				break;
			}
		}
		return requestedTable;
	}

	@Override
	public ConfigurationValue getAqqResponseMappingConfiguration() {
		return loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.AQQ).findChild("Mappings");
	}

	@Override
	public String getInternalAqqResponseCode(String aqqResponseCodeFromHost) {
		Set<ConfigurationValue> aqqResponseMappings = getAqqResponseMappingConfiguration().getChildValues();
		for (ConfigurationValue configValue : aqqResponseMappings) {
			if (aqqResponseCodeFromHost.equals((configValue.getValue()))) {
				return configValue.getKeyName();
			}
		}
		return null;
	}

	@Override
	public String getAqqServiceSuccessText() {
		Set<ConfigurationValue> aqqResponseMappings = getAqqResponseMappingConfiguration().getChildValues();
		for (ConfigurationValue configValue : aqqResponseMappings) {
			if ("API OK".equals((configValue.getValue()))) {
				return configValue.getKeyName();
			}
		}
		return null;
	}

	@Override
	public boolean isAqqFeatureEnabled() {
		return this.isFeatureOn(CheckInFeature.AQQ);
	}

	/* (non-Javadoc)
	 * @see SharedCheckInConfiguration#getCountryCodeConverter()
	 */
	@Override
	public CountryCodeConverter getCountryCodeConverter() {
		return new CountryCodeConverterImpl(this.countryAirportCode);
	}

	/* (non-Javadoc)
	 * @see SharedCheckInConfiguration#getAirportCountryConverter()
	 */
	@Override
	public AirportCountryMapper getAirportCountryMapper() {
		return new AirportCountryMapperImpl(this.countryAirportCode);
	}

    /**
     * Required implementation.
     *
     * @see CommonCheckInConfiguration#getAvailableCountries()
     */
    @Override
    public Collection<CountryReference> getAvailableCountries() {
        return this.countryAirportCode.getCountryReferences();
    }

    /**
     * Required implementation.
     *
     * @see SharedCheckInConfiguration#getCountryInformation(String)
     */
    @Override
    public CountryReference getCountryInformation(String countryCode) {
        return this.countryAirportCode.getCountryReference(countryCode);
    }

    /**
     * Required implementation.
     *
     * @see SharedCheckInConfiguration#getCountriesRequiringResidentData()
     */
    @Override
    public List<String> getCountriesRequiringResidentData() {
        ConfigurationValue intlDocsParent = loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.INTERNATIONAL_DOCUMENTS);
        ConfigurationValue countryList = intlDocsParent.findChild("ResidentDataNeeded");

        if (null == countryList) {
            throw new ConfigurationServiceException("Unable to find list of countries requiring resident data", null);
        }

        List<String> identifiedCountries = new ArrayList<String>();
        for (ConfigurationValue countryValue : countryList.getChildValues()) {
            Boolean enabled = (Boolean) countryValue.getValue();
            if (Boolean.TRUE.equals(enabled)) {
                identifiedCountries.add(countryValue.getKeyName());
            }
        }

        return identifiedCountries;
    }

    /**
     * Required implementation.
     *
     * @see SharedCheckInConfiguration#getCountriesRequiringDestinationAddress()
     */
    @Override
    public List<String> getCountriesRequiringDestinationAddress() {
        ConfigurationValue intlDocsParent = loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.INTERNATIONAL_DOCUMENTS);
        ConfigurationValue countryList = intlDocsParent.findChild("DestinationAddressNeeded");

        if (null == countryList) {
            throw new ConfigurationServiceException("Unable to find list of countries requiring destination address", null);
        }

        List<String> identifiedCountries = new ArrayList<String>();
        for (ConfigurationValue countryValue : countryList.getChildValues()) {
            Boolean enabled = (Boolean) countryValue.getValue();
            if (Boolean.TRUE.equals(enabled)) {
                identifiedCountries.add(countryValue.getKeyName());
            }
        }

        return identifiedCountries;
    }

    /**
     * Required implementation.
     *
     * @see SharedCheckInConfiguration#getCountriesRequiringI94OnDeparture()
     */
    @Override
    public List<String> getCountriesRequiringI94OnDeparture() {
        ConfigurationValue intlDocsParent = loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.INTERNATIONAL_DOCUMENTS);
        ConfigurationValue countryList = intlDocsParent.findChild("I94Needed");

        if (null == countryList) {
            throw new ConfigurationServiceException("Unable to find list of countries requiring I-94 on departure", null);
        }

        List<String> identifiedCountries = new ArrayList<String>();
        for (ConfigurationValue countryValue : countryList.getChildValues()) {
            Boolean enabled = (Boolean) countryValue.getValue();
            if (Boolean.TRUE.equals(enabled)) {
                identifiedCountries.add(countryValue.getKeyName());
            }
        }

        return identifiedCountries;
    }

    /**
     * Required implementation.
     *
     * @see SharedCheckInConfiguration#getVisaHealthURL(String)
     */
    @Override
    public String getVisaHealthURL(String language) {
        ConfigurationValue intlDocsParent = loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.INTERNATIONAL_DOCUMENTS);
        ConfigurationValue urlList = intlDocsParent.findChild("VisaHealthUrl");

        if (null == urlList) {
            throw new ConfigurationServiceException("Unable to find list of URLs for Visa/Health information", null);
        }

        String identifiedUrl = null;
        for (ConfigurationValue urlValue : urlList.getChildValues()) {
            if ((null != language) && language.equals(urlValue.getKeyName())) {
                identifiedUrl = (String) urlValue.getValue();
                break;
            }
        }

        return identifiedUrl;
    }

    /**
     * Required implementation.
     *
     * @see CommonCheckInConfiguration#getCountrySubdivisions(String)
     */
    @Override
    public List<ConfiguredPair> getCountrySubdivisions(String countryCode) {
        ConfigurationValue intlDocsParent = loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.INTERNATIONAL_DOCUMENTS);
        ConfigurationValue subdivisionList = intlDocsParent.findChild("SubdivisionsPerCountry");

        if (null == subdivisionList) {
            throw new ConfigurationServiceException("Unable to find list of subdivisions for country " + countryCode, null);
        }

        List<ConfiguredPair> subdivisions = new ArrayList<ConfiguredPair>();
        for (ConfigurationValue countryValue : subdivisionList.getChildValues()) {
            if ((null != countryCode) && countryCode.equals(countryValue.getKeyName())) {
                Boolean enabled = (Boolean) countryValue.getValue();
                if (Boolean.TRUE.equals(enabled)) {
                    Set<ConfigurationValue> subdivisionRefs = countryValue.getChildValues();
                    for (ConfigurationValue subDivRef : subdivisionRefs) {
                        String name = subDivRef.getKeyName();
                        String value = subDivRef.getValue().toString();
                        ConfiguredPair pair = new ConfiguredPair(name, value);
                        subdivisions.add(pair);
                    }
                }
                break;
            }
        }

        return subdivisions;
    }

    /**
     * Required implementation.
     *
     * @see CommonCheckInConfiguration#getParentCountry(String)
     */
    @Override
    public String getParentCountry(String countryCode) {
        ConfigurationValue intlDocsParent = loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.INTERNATIONAL_DOCUMENTS);
        ConfigurationValue territoryList = intlDocsParent.findChild("TerritoryCountry");

        if (null == territoryList) {
            throw new ConfigurationServiceException("Unable to find list of potential parents for country " + countryCode, null);
        }

        String parentCountry = countryCode;
        Boolean enabled = (Boolean) territoryList.getValue();
        if (Boolean.TRUE.equals(enabled)) {
            for (ConfigurationValue countryValue : territoryList.getChildValues()) {
                if ((null != countryCode) && countryCode.equals(countryValue.getKeyName())) {
                    parentCountry = countryValue.getValue().toString();
                    break;
                }
            }
        }

        return parentCountry;
    }

    /**
     * Required implementation; initializes pre-loaded data.
     *
     * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
     */
    @Override
    public void afterPropertiesSet() {
      try {
          // FIXME: This logic needs to be handled in a different fashion. It is understood that this load results in
          // complex processing; however, this implementation leads to some unstable edge case behavior (especially
          // for testing)
        this.countryAirportCode.initializeMappings(loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.COUNTRIES));
      } catch (ConfigurationServiceException e) {
          logger.warn("Post-instantiation initialization failed", e);
      }
    }

    /**
     * Required implementation.
     *
     * @see com.ncr.travel.airline.shared.configuration.checkin.CommonCheckInConfigurationImpl#reset()
     */
    @Override
    public void reset() {
        super.reset();
        afterPropertiesSet();
    }

	@Override
	public FeatureSettings getSettingsForFeature(CheckInFeature feature) {
		ConfigurationValueTemplate template;
		switch(feature){
		case REDRESS_NUMBER:{
			template = loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.INTERNATIONAL_DOCUMENTS).findChild("RedressNumber").getTemplate();
			return new FeatureSettings(null, null, (Integer)template.getMinimumValue(), (Integer)template.getMaximumValue(), template.isReadOnly(), template.isRequired(), template.getRegularExpression());
			}
			default:
			return null;
		}
	}

	/**
	 * Required implementation.
	 *
	 * @see SharedCheckInConfiguration#getMinimumGroupSize()
	 */
	@Override
	public int getMinimumGroupSize() {
		ConfigurationValue groupSettings = getGroupCheckInSettings();
		ConfigurationValue minimumSize = groupSettings.findChild("MinimumGroupSize");
		
		if (null == minimumSize) {
            throw new ConfigurationServiceException("Unable to find group size settings", null);
		}
		
		return ((Integer) minimumSize.getValue()).intValue();
	}

	/**
	 * Required implementation.
	 *
	 * @see SharedCheckInConfiguration#getMaximumGroupSize()
	 */
	@Override
	public int getMaximumGroupSize() {
		ConfigurationValue groupSettings = getGroupCheckInSettings();
		ConfigurationValue maximumSize = groupSettings.findChild("MaximumGroupSize");
		
		if (null == maximumSize) {
            throw new ConfigurationServiceException("Unable to find group size settings", null);
		}
		
		return ((Integer) maximumSize.getValue()).intValue();
	}

	/**
	 * Required implementation.
	 *
	 * @see SharedCheckInConfiguration#isSurnameGroupingEnabled()
	 */
	@Override
	public boolean isSurnameGroupingEnabled() {
		ConfigurationValue groupSettings = getGroupCheckInSettings();
		ConfigurationValue surnameMatch = groupSettings.findChild("GroupOnSurname");
		
		if (null == surnameMatch) {
            throw new ConfigurationServiceException("Unable to find surname grouping settings", null);
		}
		
		return ((Boolean) surnameMatch.getValue()).booleanValue();
	}

	/**
	 * Obtains the configuration root for group check-in configuration.
	 * 
	 * @return the retrieved content
	 * @throws ConfigurationServiceException if the configuration is not present
	 */
	private ConfigurationValue getGroupCheckInSettings() {
		ConfigurationValue groupSettings = loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.GROUP_CHECKIN);
		if (null == groupSettings) {
            throw new ConfigurationServiceException("Unable to find group check-in settings", null);
		}
		
		return groupSettings;
	}

	/**
	 * Required implementation.
	 *
	 * @see SharedCheckInConfiguration#getAllowedReservationTypes()
	 */
	@Override
	public List<String> getAllowedReservationTypes() {
        ConfigurationValue validationParent = loadValueFromService(ConfigurationNodeEnum.GLOBAL, ConfigurationProductKey.SHARED, ConfigurationKey.VALIDATIONS);

        ConfigurationValue reservationParent = validationParent.findChild("RESERVATION");
        if (null == reservationParent) {
            throw new ConfigurationServiceException("Unable to find reservation validations", null);
        }

        ConfigurationValue typeParent = reservationParent.findChild("ReservationType");
        if (null == typeParent) {
            throw new ConfigurationServiceException("Unable to find list of reservation types", null);
        }

        List<String> allowedTypes = new ArrayList<String>();
        for (ConfigurationValue typeValue : typeParent.getChildValues()) {
            Boolean enabled = (Boolean) typeValue.getValue();
            if (Boolean.TRUE.equals(enabled)) {
            	allowedTypes.add(typeValue.getKeyName());
            }
        }

        return allowedTypes;
	}
	
}
